/*
	Visp is an opensource visual performance application built with Adobe® AIR™.
	
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
	
	Mike Creighton can be found at http://www.mikecreighton.com	
*/
package com.visp.midi {
	
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.XMLSocket;
	import flash.xml.XMLNode;
	
	[Event(name="controller", type="com.visp.midi.ControllerEvent")]
	[Event(name="noteOff", type="com.visp.midi.NoteEvent")]
	[Event(name="noteOn", type="com.visp.midi.NoteEvent")]
	[Event(name="programChange", type="com.visp.midi.ProgramChangeEvent")]

	public class MidiManager extends EventDispatcher {
		
		private static var $midiValueHashTable : Object;
		private static var $instance : MidiManager;
		private var $xmlSocket : XMLSocket;
		
		public static function getInstance() : MidiManager {
			if($instance == null){
				$instance = new MidiManager();
			}
			return $instance;
		}
		
		public function MidiManager() {
			$midiValueHashTable = new Object();
			for(var i : int = 0; i < 128; i++){
				$midiValueHashTable[i.toString(10)] = i/127;
			}
		}
		
		public function initialize() : void {
			$xmlSocket = new XMLSocket();
			$xmlSocket.addEventListener(Event.CONNECT, $handleSocketConnected);
			$xmlSocket.addEventListener(DataEvent.DATA, $handleSocketData);
			$xmlSocket.addEventListener(IOErrorEvent.IO_ERROR, $handleSocketIOError);
			$xmlSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, $handleSocketSecurityError);
			try{
				$xmlSocket.connect("127.0.0.1", 10000);
			} catch (e : SecurityError) {
				trace("MidiManager.initialize() > There was a security error when attempting to connect to the socket.");
			}
		}
		
		private function $handleSocketData(e : DataEvent) : void {
			var data : XML = new XML(e.data);
			
			switch(data.name().toString()){
				case "c":
					// Receives a n attr
					// Receives a d attr
					dispatchEvent(new ControllerEvent(ControllerEvent.CONTROLLER, uint(parseInt(data.@n)), MidiManager.$midiValueHashTable[data.@d]));
				break;
				
				case "n1":
					// Receives a p attr
					// Receives a v attr
					var p : int = int(parseInt(data.@p));
					var noteEvent : NoteEvent = new NoteEvent(NoteEvent.NOTE_ON, p);
					noteEvent.velocity = MidiManager.$midiValueHashTable[data.@v];
					this.dispatchEvent(noteEvent);
				break;
				
				case "n0":
					// Receives a p attr
					var pitchOff : int = int(parseInt(data.@p));
					var noteOffEvent : NoteEvent = new NoteEvent(NoteEvent.NOTE_OFF, pitchOff);
					noteOffEvent.velocity = 0;
					this.dispatchEvent(noteOffEvent);
				break;
				
				case "p":
					// Receives a n attr
					dispatchEvent(new ProgramChangeEvent(ProgramChangeEvent.PROGRAM_CHANGE, uint(parseInt(data.@n))));
				break;
			}
		}
		
		private function $handleSocketConnected(e : Event) : void {
			dispatchEvent(new Event(Event.CONNECT));
		}
		
		private function $handleSocketIOError(e : IOErrorEvent) : void {
			trace("MidiManager > Socket > IO Error > " + e.text);
		}
		
		private function $handleSocketSecurityError(e : SecurityErrorEvent) : void {
			trace("MidiManager > Socket > Security Error > " + e.text);
		}
	}
}